home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
dviware
/
dvidvi
/
dvidvi.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-06-30
|
33KB
|
1,199 lines
/*
* This program converts dvi files to dvi files;
* the command line options are:
*
* page n is first page selected -f n
* page n is last page selected -l n
* print at most n pages -n n
* include pages (ranges allowed) -i { n1..n2 | n1 }[,...]
* exclude pages (ranges allowed) -x { n1..n2 | n1 }[,...]
* work in quiet mode -q
* reverse pages -r
* select even -m 2:1
* select odd -m 2:0
* print both on same page -m 2:0,1(5.5in,0in)
* do folded brochures -m 4:-3,0(5.5in,0in)
* -m 4:1,-2(5.5in,0in)
* etc.
*
* The original program is by Tomas Rokicki (version 0.5) but it was
* modified and improved by Esteban ZIMANYI ezimanyi@rc1.vub.ac.be
* to give version 1.0.
*
* This version has been tested for the IBM PC and compatibles under
* compilers Turbo C 2.0 and Microsoft C 6.0.
*
*/
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#define BANNER "\nThis is dvidvi 1.0, Copyright (C) 1988-91, Radical Eye Software\n"
#define STRINGSIZE (500) /* maximum number of strings in program */
#ifndef VMS
#include <stdio.h>
#include <string.h>
#else /* VMS */
#include "sys$library:stdio.h" /* AKT: added sys$library: */
#include <alloc.h>
#endif /* VMS */
#define MAXPPERP (32)
/* defines READBIN, WRITEBIN, PATHSEP and DIRSEP*/
#ifdef MSDOS
#define READBIN "rb" /* MSDOS must use binary mode */
#define WRITEBIN "wb"
#define PATHSEP ';'
#define DIRSEP '\\'
#else
#ifdef VMS
#define READBIN "rb" /* VMS must use binary mode */
#define WRITEBIN "wb"
#define PATHSEP ','
#define DIRSEP ':'
#else
#define READBIN "r" /* UNIX doesn't care */
#define WRITEBIN "w"
#define PATHSEP ':'
#define DIRSEP '/'
#endif
#endif
#ifdef XENIX
#define SHORTINT
#else
#undef SHORTINT
#endif
#ifdef MSDOS
#define SHORTINT
#endif
/*
* Type declarations. integer must be a 32-bit signed; shalfword must
* be a sixteen-bit signed; halfword must be a sixteen-bit unsigned;
* quarterword must be an eight-bit unsigned.
*/
typedef long integer;
typedef char boolean;
typedef short shalfword ;
typedef unsigned short halfword ;
typedef unsigned char quarterword ;
typedef short Boolean ;
/*
* Some globals to keep everyone happy.
*/
integer numpages ; /* the total number of pages in the dvi file. */
integer TeXfonts[256] ; /* information about each font */
char fontseen[256] ; /* have we defined this font yet? */
int modulo ; /* our mod value */
struct pagespec {
int pageno, reversed ;
long hoffset, voffset ; /* in scaled points */
} pages[MAXPPERP] ; /* the organization of the pages on output */
int pagesperpage ; /* how many pages crammed onto each page? */
FILE *infile ; /* input dvi file (cannot be a stream) */
FILE *outfile ; /* output dvi file */
char *temp ; /* a temporary place to put things */
char *nextstring, *maxstring ;
char *oname ; /* output dvi file name */
char *iname ; /* input dvi file name */
char *strings ; /* pointer of the string pool */
char banner[] = BANNER ; /* the startup message */
integer inlength ; /* the length of the input dvi file */
integer postloc ; /* location of the postamble */
integer mag ; /* magnification factor */
integer pagecount ; /* number of actual pages */
integer landscape = 0; /* if landscape special, here it is! */
int rem0special ; /* should we remove the first first-page special? */
integer prevpp = -1 ; /* previous page pointer on output */
integer outputpages ; /* number of pages output */
integer dviloc ; /* our position in the output file */
integer pagefake ; /* number of pages, rounded up to multiple of modulo */
Boolean firsttransf = 0, lasttransf = 0;
integer firstpage ; /* first page selected (option -p) */
integer lastpage ; /* last page selected (option -l) */
integer maxpages ; /* maximum number of page selected (option -n) */
short quiet ; /* quiet mode (option -q) */
Boolean exctransf[40][2] ; /* if the ranges of pages to exclude (option -x)
have to be transformed */
integer exclude[40][2] ; /* the ranges of pages to exclude (option -x)
It is supposed that there are at most 40 ranges
to exclude in the command line */
short excludeseq ; /* number of ranges to exclude (option -x) */
Boolean inctransf[40][2] ; /* if the ranges of pages to exclude (option -x)
have to be transformed */
integer include[40][2] ; /* the ranges of pages to include (option -i)
It is supposed that there are at most 40 ranges
to include in the command line */
short includeseq ; /* number of ranges to include (option -i) */
integer *pageloc ;
integer *pagenumbers ;
int prettycolumn ; /* the column we are at when running pretty */
/*
* This array holds values that indicate the length of a command, if
* we aren't concerned with that command (which is most of them) or
* zero, if it is a special case. This makes running through the
* dvi file a lot easier (and probably faster) than any form of
* dispatch table, especially since we really don't care what the
* pages are made of.
*/
short comlen[256] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0-15 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 16-31 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 32-47 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 48-63 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80-95 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 112-127 */
2, 3, 4, 5, 9, 2, 3, 4, 5, 9, 1, 0, 0, 1, 1, 2, /* 128-143 */
3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 2, 3, 4, /* 144-159 */
5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, /* 160-175 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 176-191 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192-207 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 208-223 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 5, 0, /* 224-239 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };/* 240-255 */
/*
* Input bytes from the dvi file.
* These routines could probably be sped up significantly; but they are
* very machine dependent, so I will leave such tuning to the installer.
* They simply get and return bytes in batches of one, two, three, and four,
* updating the current position as necessary.
*/
void
abortpage()
{
error("! unexpected eof on DVI file") ;
}
shalfword dvibyte()
{
register shalfword i ;
if ((i=getc(infile))==EOF)
abortpage() ;
return(i) ;
}
halfword twobytes()
{
register halfword i ;
i = dvibyte() ;
return(i*256+dvibyte()) ; }
integer threebytes()
{
register integer i ;
i = twobytes() ;
return(i*256+dvibyte()) ; }
shalfword
signedbyte()
{
register shalfword i ;
if ((i=getc(infile))==EOF)
abortpage() ;
if (i<128) return(i) ;
else return(i-256) ;
}
shalfword
signedpair()
{
register shalfword i ;
i = signedbyte() ;
return(i*256+dvibyte()) ;
}
integer
signedtrio()
{
register integer i ;
i = signedpair() ;
return(i*256+dvibyte()) ;
}
integer
signedquad()
{
register integer i ;
i = signedpair() ;
return(i*65536+twobytes()) ;
}
/*
* Routines for the transformation of the pages specified with
* the @ parameter into the actual number of page from the file
*
* trans(p,q) looks for the q'th occurrence of the page numbered p
* transformpages makes the transformation for the options -f -i -l -x
*/
integer transf(p,q)
integer p;
halfword q;
{
int i=0, j=0;
while( j != q && i < pagecount )
if ( pagenumbers[i++] == p ) j++;
if ( j != q ) error ("! Page specified not found");
return (i++);
}
void transformpages()
{
int i;
if (firsttransf) firstpage=transf(firstpage,firsttransf);
if (lasttransf) lastpage=transf(lastpage,lasttransf);
for ( i= 0; i< 40; i++) {
if (exctransf[i][0]) exclude[i][0]=transf(exclude[i][0],exctransf[i][0]);
if (exctransf[i][1]) exclude[i][1]=transf(exclude[i][1],exctransf[i][1]);
if (inctransf[i][0]) include[i][0]=transf(include[i][0],inctransf[i][0]);
if (inctransf[i][1]) include[i][1]=transf(include[i][1],inctransf[i][1]);
}
}
/*
*
*/
integer fontdeflen(p)
integer p;
{
fseek(infile,p+14,SEEK_SET);
return (16L+dvibyte()+dvibyte());
}
/*
* Simulation of dvibuf, get the character located at the position
* p in the input dvi file
*/
unsigned char dvibuf(p)
integer p;
{
fseek(infile,p,SEEK_SET);
return(dvibyte());
}
/*
* Read a string of length n from the file into the string temp
*/
void stringdvibuf(p,n)
integer p,n;
{
fseek(infile,p,SEEK_SET);
while ( n-- > 0 )
*temp++ = dvibyte();
}
/*
* Print a usage error messsage, and quit.
*/
usage() {
(void)fprintf(stderr,banner);
(void)fprintf(stderr,"Usage: dvidvi [options] input[.dvi] [output]\n");
(void)fprintf(stderr,"where options are:\n");
(void)fprintf(stderr," [-f n] first page printed [-l n] last page printed\n");
(void)fprintf(stderr," [-n n] print at most n pages \n");
(void)fprintf(stderr," [-i {n1..n2 | n3}[,...]] include pages\n");
(void)fprintf(stderr," [-x {n1..n2 | n3}[,...]] exclude pages\n");
(void)fprintf(stderr," [-q] quiet mode [-r] reverse pages\n");
(void)fprintf(stderr," [-m modulo:pagespecs]\n");
#ifndef VMS
exit(1) ;
#else /* VMS */
exit(0x10000002) ;
/* AKT: was exit(1) */
#endif /* VMS */
}
/*
* Print an error message, and exit if it is fatal.
*/
error(s)
char *s ;
{
(void)fprintf(stderr, "%s\n", s) ; /* AKT: was dvidvi: %s */
if (*s == '!')
#ifndef VMS
exit(1) ;
#else /* VMS */
exit(0x10000002) ;
/* AKT: was exit(1) */
#endif /* VMS */
}
/*
* This function calculates approximately (whole + num/den) * sf.
* No need for real extreme accuracy; one ten thousandth of an
* inch should be sufficient.
*
* No `sf' parameter means to use an old one; inches are assumed
* originally.
*
* Assumptions:
*
* 0 <= num < den <= 10000
* 0 <= whole
*/
integer defaultscale = 4736286 ;
integer scale(whole, num, den, sf)
integer whole, num, den, sf ;
{
integer v ;
if (sf)
defaultscale = sf ;
else
sf = defaultscale ;
v = whole * sf + num * (sf / den) ;
if (v / sf != whole || v < 0 || v > 0x40000000L)
error("! arithmetic overflow in parameter") ;
sf = sf % den ;
v += (sf * num * 2 + den) / (2 * den) ;
return(v) ;
}
/*
* Multiplies *p by 1000 and divides it by mag. Avoiding overflow.
*
* 1 <= mag <= 1000000 ;
* 0 <= *p <= 2^30
*
* (Could blow up if a parameter * mag / 1000 > 2^30 sp.)
*/
scalemag(p)
long *p ;
{
int negative ;
negative = 0 ;
if (*p < 0) {
negative = 1 ;
*p = - *p ;
}
*p = 1000 * (*p / mag) + (2000 * (*p % mag) + mag) / (2 * mag) ;
if (negative)
*p = - *p ;
}
/*
* Convert a sequence of digits into an integer; return -1 if no digits.
* Advance the passed pointer as well.
*/
integer myatol(s)
char **s ;
{
register char *p ;
register integer result ;
result = 0 ;
p = *s ;
while ('0' <= *p && *p <= '9') {
if (result > 100000000)
error("! arithmetic overflow in parameter") ;
result = 10 * result + *p++ - '0' ;
}
if (p == *s)
usage() ;
else {
*s = p ;
return(result) ;
}
}
/*
* Get a dimension, allowing all the various extensions, and
* defaults.
*/
integer myatodim(s)
char **s ;
{
register integer w, num, den ;
register char *p ;
int negative = 0 ;
p = *s ;
if (**s == '-') {
(*s)++ ;
negative = 1 ;
}
w = myatol(s) ;
if (w < 0)
usage() ;
p = *s ;
num = 0 ;
den = 1 ;
if (*p == '.') {
p++ ;
while ('0' <= *p && *p <= '9') {
if (den < 1000) {
den *= 10 ;
num = num * 10 + *p - '0' ;
}
p++ ;
}
}
/*
* Allowed units are `in', `cm', `mm', `pt', `sp', `cc', `dd', and `pc';
* must be in lower case.
*/
if (*p == 'c' && p[1] == 'm') {
/* centimeters need to be multiplied by 72.27 * 2^16 / 2.54, or 1 864 680 */
w = scale(w, num, den, 1864680L) ;
} else if (*p == 'p' && p[1] == 't') {
/* real points need to be multiplied by 2^16 */
w = scale(w, num, den, 65536L) ;
} else if (*p == 'p' && p[1] == 'c') {
/* picas need to be multiplied by 65536 * 12, or 786 432 */
w = scale(w, num, den, 786432L) ;
} else if (*p == 'm' && p[1] == 'm') {
/* millimeters need to be multiplied by 72.27 * 2^16 / 25.4, or 186 468 */
w = scale(w, num, den, 186468L) ;
} else if (*p == 's' && p[1] == 'p') {
/* scaled points are already taken care of; simply round */
w = scale(w, num, den, 1L) ;
} else if (*p == 'b' && p[1] == 'p') {
/* big points need to be multiplied by 72.27 * 65536 / 72, or 65782 */
w = scale(w, num, den, 65782L) ;
} else if (*p == 'd' && p[1] == 'd') {
/* didot points need to be multiplied by 65536 * 1238 / 1157, or 70124 */
w = scale(w, num, den, 70124L) ;
} else if (*p == 'c' && p[1] == 'c') {
/* cicero need to be multiplied by 65536 * 1238 / 1157 * 12, or 841 489 */
w = scale(w, num, den, 841489L) ;
} else if (*p == 'i' && p[1] == 'n') {
/* inches need to be multiplied by 72.27 * 65536, or 4 736 286 */
w = scale(w, num, den, 4736286L) ;
} else {
/* use default values */
w = scale(w, num, den, 0L) ;
p -= 2 ;
}
p += 2 ;
*s = p ;
return(negative?-w:w) ;
}
/*
* This function determine if the page has to be printed
* depending on the values of options -f, -l, -i and -x
*/
short selectedpage (n)
integer n;
{
short i;
if ( firstpage > n || n > lastpage ) return(0);
for ( i=0 ; i < excludeseq ; i++ )
if ( exclude[i][0] <= n && n <= exclude[i][1] )
return(0);
if (includeseq == 0) return (1);
for ( i=0 ; i < includeseq ; i++ )
if ( include[i][0] <= n && n <= include[i][1] )
return(1);
return(0);
}
/*
* Initialize sets up all the globals and data structures.
*/
void
initialize()
{
int i;
/* initialize values in case of option -m is not specified */
modulo = 1 ;
pages[0].hoffset = 0 ;
pages[0].voffset = 0 ;
pages[0].pageno = 0 ;
pages[0].reversed = 0 ;
pagesperpage = 1 ;
for ( i= 0; i< 40; i++) {
exctransf[i][0] = exctransf[i][1] = 0;
inctransf[i][0] = inctransf[i][1] = 0;
}
firsttransf = lasttransf = 0;
excludeseq = 0;
includeseq = 0;
firstpage = 1;
lastpage = 1000000;
maxpages = 1000000;
quiet = 0;
strings =(char *) malloc(STRINGSIZE) ;
if (strings == 0)
error("! no memory for strings") ;
maxpages = 100000 ;
nextstring = strings ;
iname = strings ;
*nextstring++ = 0 ;
maxstring = strings + STRINGSIZE - 200;
}
/*
* Parse the arguments to the routine, and stuff everything away
* into those globals above.
*/
processargs(argc, argv)
int argc ;
char *argv[] ;
{
char *p, *q ;
int i, pageno, lastext = -1 ;
long hoffset, voffset ;
int reversed ;
initialize ();
if (argc < 2 || argc > 8)
usage() ;
/*
* This next whole big section of code is straightforward; we just scan
* the options. An argument can either immediately follow its option letter
* or be separated by spaces. Any argument not preceded by '-' and an
* option letter is considered a file name.
*/
for (i=1; i<argc; i++) {
if (*argv[i]=='-') {
char *p=argv[i]+2 ;
char c=argv[i][1] ;
switch (c) {
case 'f' :
if (*p == 0 && argv[i+1])
p = argv[++i] ;
if (*p == '(' && *(p+1) == '@' ) {
p+=2; firsttransf = myatol(&p); p++;
}
else if (*p == '@') {
p++; firsttransf = 1 ;
}
#ifdef SHORTINT
if(sscanf(p, "%d", &firstpage)==0)
#else /* ~SHORTINT */
if(sscanf(p, "%ld", &firstpage)==0)
#endif /* ~SHORTINT */
error("! Bad first page option (-f).") ;
break ;
case 'i' :
if (*p == 0 && argv[i+1])
p = argv[++i] ;
while (*p != 0) {
if (*p == '(' && *(p+1) == '@' ) {
p+=2; inctransf[includeseq][0] = myatol(&p); p++;
}
else if (*p == '@') {
p++; inctransf[includeseq][0] = 1 ;
}
include[includeseq][0]=myatol(&p);
if (*p == '.' && *(p+1) == '.' ) {
p += 2;
if (*p == '(' && *(p+1) == '@' ) {
p+=2; inctransf[includeseq][1] = myatol(&p); p++;
}
else if (*p == '@') {
p++; inctransf[includeseq][1] = 1 ;
}
include[includeseq][1] = myatol(&p);
}
else {
include[includeseq][1] = include[includeseq][0];
inctransf[includeseq][0] = inctransf[includeseq][1] ;
}
includeseq++ ;
if (*p != ',' && *p !=0 )
error("! Bad page range option (-i).") ;
if (*p == ',' )
p++ ;
} /* while */
break ;
case 'l':
if (*p == 0 && argv[i+1])
p = argv[++i] ;
if (*p == '(' && *(p+1) == '@' ) {
p+=2; lasttransf = myatol(&p); p++;
}
else if (*p == '@') {
p++; lasttransf = 1 ;
}
#ifdef SHORTINT
if(sscanf(p, "%ld", &lastpage)==0)
#else /* ~SHORTINT */
if(sscanf(p, "%d", &lastpage)==0)
#endif /* ~SHORTINT */
error("! Bad last page option (-l).") ;
break ;
case 'm' :
if (*p == 0 && argv[i+1])
p = argv[++i] ;
/*
* Is there a modulo supplied? Grab it if so; otherwise default to 1.
*/
for (q=p; *q != 0; q++)
if (*q == ':')
break ;
if (*q == ':') {
modulo = myatol(&p) ;
if (*p != ':')
usage() ;
if (modulo < 1 || modulo > MAXPPERP)
error("! modulo must lie between 1 and 32") ;
p++ ;
}
/*
* This loop grabs all of the page specifications.
*/
pagesperpage = 0 ;
while (*p != 0) {
if (pagesperpage >= MAXPPERP)
error("! too many page specifications") ;
if (*p == '-') {
reversed = 1 ;
p++ ;
} else
reversed = 0 ;
if (*p == 0 || *p == '(' || *p == ',')
pageno = 0 ;
else
pageno = myatol(&p) ;
if (*p == '(') {
p++ ;
hoffset = myatodim(&p) ;
if (*p++ != ',')
usage() ;
voffset = myatodim(&p) ;
if (*p++ != ')')
usage() ;
} else {
hoffset = 0 ;
voffset = 0 ;
}
pages[pagesperpage].hoffset = hoffset ;
pages[pagesperpage].voffset = voffset ;
pages[pagesperpage].pageno = pageno ;
pages[pagesperpage].reversed = reversed ;
pagesperpage++ ;
if (*p == ',')
p++ ;
} /* while */
break ;
case 'n' :
if (*p == 0 && argv[i+1])
p = argv[++i] ;
#ifdef SHORTINT
if (sscanf(p, "%ld", &maxpages)==0)
#else /* ~SHORTINT */
if (sscanf(p, "%d", &maxpages)==0)
#endif /* ~SHORTINT */
error("! Bad number of pages option (-n).") ;
break ;
case 'q' : case 'Q' :
quiet = 0 ;
break ;
case 'r' : case 'R' :
pages[0].reversed = 1;
break ;
case 'x' :
if (*p == 0 && argv[i+1])
p = argv[++i] ;
while (*p != 0) {
if (*p == '(' && *(p+1) == '@' ) {
p+=2; exctransf[excludeseq][0] = myatol(&p); p++;
}
else if (*p == '@') {
p++; exctransf[excludeseq][0] = 1 ;
}
exclude[excludeseq][0]=myatol(&p);
if (*p == '.' && *(p+1) == '.' ) {
p += 2;
if (*p == '(' && *(p+1) == '@' ) {
p+=2; exctransf[excludeseq][1] = myatol(&p); p++;
}
else if (*p == '@') {
p++; exctransf[excludeseq][1] = 1 ;
}
exclude[excludeseq][1] = myatol(&p);
}
else {
exclude[excludeseq][1] = exclude[excludeseq][0];
exctransf[excludeseq][0] = exctransf[excludeseq][1] ;
}
excludeseq++ ;
if (*p != ',' && *p !=0 )
error("! Bad page range option (-x).") ;
if (*p == ',' )
p++ ;
} /* while */
break ;
case '?' :
usage() ;
break ;
default:
error("! Bad option, not one of filmnqrx?") ;
} /* switch c */
} else { /* this a file name */
if (*iname == 0) { /* input file name */
register char *p ;
lastext = 0 ;
iname = nextstring ;
p = argv[i] ;
while (*p) {
*nextstring = *p++ ;
if (*nextstring == '.')
lastext = nextstring - iname ;
else if (*nextstring == '/' || *nextstring == ':')
lastext = 0 ;
nextstring++ ;
}
if (lastext == 0) {
lastext = nextstring - iname ;
*nextstring++ = '.' ;
*nextstring++ = 'd' ;
*nextstring++ = 'v' ;
*nextstring++ = 'i' ;
}
*nextstring++ = 0 ;
if ((infile=fopen(iname, READBIN))==NULL)
error("! can't open input file") ;
} else { /* output file name */
register char *p ;
lastext = 0 ;
oname = nextstring ;
p = argv[i] ;
while (*p) {
*nextstring = *p++ ;
if (*nextstring == '.')
lastext = nextstring - oname ;
else if (*nextstring == '/' || *nextstring == ':')
lastext = 0 ;
nextstring++ ;
}
if (lastext == 0) {
lastext = nextstring - oname ;
*nextstring++ = '.' ;
*nextstring++ = 'd' ;
*nextstring++ = 'v' ;
*nextstring++ = 'i' ;
}
*nextstring++ = 0 ;
if (freopen(oname, WRITEBIN, stdout)==NULL)
error("! can't open output file") ;
} /* end output file name */
} /* else argument with '-' */
} /* for */
if (*iname == 0) {
(void)fprintf(stderr, banner) ;
error("! no input file specified");
}
if (*oname != 0 && !quiet) {
(void)fprintf(stderr, banner) ;
(void)fprintf(stderr, "%s -> %s\n",iname,oname);
temp = nextstring ;
}
}
/*
* Grabs a pointer, and checks it for validity.
*/
integer ptr(where)
register integer where ;
{
fseek(infile,where,SEEK_SET);
where = signedquad() ;
if (where < -1L || where > inlength)
error("! dvi file malformed; impossible pointer") ;
return(where) ;
}
/*
* This routine store the page locations by tracing the pointers backwards.
*/
void searchpageloc()
{
integer p,num ;
num=pagecount-1;
for (p = ptr(postloc+1); num > 0; num--) {
if (dvibuf(p) != 139)
error("! missed a bop somehow") ;
else {
pageloc[num]=p;
pagenumbers[num]=signedquad();
}
p = ptr(p+41) ;
}
pageloc[num]=p;
(void)dvibuf(p);
pagenumbers[num]=signedquad();
}
/*
* This routine simply reads the entire dvi file, and then initializes
* some values about it.
*/
readdvifile() {
integer p ;
unsigned char c,d,e ;
fseek(infile, 0L, 2) ;
inlength = ftell(infile) ;
if (inlength < 10)
error("! dvi file too short") ;
fseek(infile,-3L,SEEK_CUR);
for (p=inlength - 3; p > 0; p--) {
c = dvibyte (); d = dvibyte (); e = dvibyte ();
if (c == 2 && d == 0xdf /* dave fuchs */ &&
e == 0xdf)
break ;
fseek(infile,-4L,SEEK_CUR);
}
if (p < 10)
error("! rather short dvi file, ain't it?") ;
postloc = ptr(p-4) ;
fseek(infile,postloc+5L,SEEK_SET);
if (signedquad() != 25400000 ||
signedquad() != 473628672)
error("! change this program to support non-TeX num/den values") ;
mag = signedquad() ;
if (mag < 1 || mag > 1000000)
error("! impossible magnification value") ;
fseek(infile,postloc+27L,SEEK_SET);
pagecount = twobytes() ;
if (pagecount < 1 || pagecount > 1000000)
error("! impossible page count value") ;
/*
* That's enough error checking; we probably have a correct dvi file.
* Let's convert all the values we got from the command line into
* units that we can actually use in the dvi file.
*/
for (p=0; p<pagesperpage; p++) {
scalemag(&(pages[p].hoffset)) ;
scalemag(&(pages[p].voffset)) ;
}
/*
* Now let's grab us some font pointers.
*/
pageloc = (integer *) calloc (pagecount, sizeof (integer));
if (pageloc == NULL)
error("! Not enough memory for allocation of page pointers");
pagenumbers = (integer *) calloc (pagecount, sizeof (integer));
if (pagenumbers == NULL)
error("! Not enough memory for allocation of page numbers array");
searchpageloc();
transformpages();
free(pagenumbers);
p = postloc + 29 ;
while (1) {
c=dvibuf(p);
if (c == 249)
break ;
if (c == 138)
p++ ;
else if (c == 243) {
TeXfonts[dvibyte()] = p ;
p += fontdeflen(p) ;
} else
error("! only nop's and font def's allowed in postamble") ;
}
/*
* Now we check for a landscape special. It should be the
* *first* thing in the page that is at all complicated.
*/
p = pageloc[0L] + 45 ;
c=dvibuf(p);
while (comlen[c]) {
p += comlen[c] ;
c = dvibuf(p);
}
if (c == 239) {
stringdvibuf(p+2L,9L);
if (strncmp(temp, "landscape", 9)==0) {
landscape = p ;
rem0special = 1 ;
}
}
}
/*
* Output a single byte, keeping track of where we are.
*/
outdvibyte(c)
unsigned char c ;
{
fputc(c, stdout) ;
dviloc++ ;
}
/*
* Send out two bytes.
*/
outdvi2(v)
integer v ;
{
outdvibyte((unsigned char)(v >> 8)) ;
outdvibyte((unsigned char)(v & 255)) ;
}
/*
* Send out a longword.
*/
outdviquad(v)
integer v ;
{
outdvi2(v >> 16) ;
outdvi2(v & 65535) ;
}
/*
* This routine just copies some stuff from the buffer on out.
* Suppose the file is positioned correctly before
*/
putbuf(length)
integer length ;
{
while ( length-- > 0 )
outdvibyte(dvibyte()) ;
}
/*
* This routine outputs a string, terminated by null.
*/
putstr(s)
register unsigned char *s ;
{
while (*s)
outdvibyte(*s++) ;
}
/*
* Here we write the preamble to the dvi file.
*/
writepreamble() {
/* just copy the first 14 bytes of the file */
fseek(infile,0L,SEEK_SET);
putbuf(14L) ;
/* and put our identifier. */
putstr("\015dvidvi output") ;
}
/*
* This routine writes out a font definition.
*/
putfontdef(f)
int f ;
{
integer p,q ;
p = TeXfonts[f] ;
q=fontdeflen(p) ;
fseek(infile,p,SEEK_SET);
putbuf(q) ;
}
/*
* The postamble is next.
*/
writepostamble() {
int i ;
integer p ;
p = dviloc ;
outdvibyte(248) ;
outdviquad(prevpp) ;
fseek(infile,postloc+5,SEEK_SET);
putbuf(20L) ;
outdvi2(twobytes()+1L) ; /* increase stack depth by 1 */
outdvi2(outputpages) ;
for (i=0; i<256; i++)
if (fontseen[i])
putfontdef(i) ;
outdvibyte(249) ;
outdviquad(p) ;
outdvibyte(2) ;
outdviquad(0xdfdfdfdfL) ;
while (dviloc & 3)
outdvibyte(0xdf) ;
fclose(stdout) ;
}
/*
* This routine starts a page, by writing out a bop command.
*/
beginpage() {
int i ;
integer p ;
p = dviloc ;
outdvibyte(139) ;
outdviquad(outputpages+1) ;
for (i=0; i<9; i++)
outdviquad(0L) ;
outdviquad(prevpp) ;
prevpp = p ;
}
/*
* This routine sends out a page. We need to handle the
* landscape special, though.
*/
dopage(num)
integer num ;
{
register integer p,q ;
register int len ;
integer v, oldp ;
unsigned char c;
/*
* We want to take the base 10 log of the number. It's probably
* small, so we do it quick.
*/
if (! quiet) {
int t = num+1, i = 0 ;
if (t < 0) {
t = -t ;
i++ ;
}
do {
i++ ;
t /= 10 ;
} while (t > 0) ;
if (i + prettycolumn > 76) {
fprintf(stderr, "\n") ;
prettycolumn = 0 ;
}
prettycolumn += i + 1 ;
#ifdef SHORTINT
(void)fprintf(stderr, "[%ld", num+1) ;
#else /* ~SHORTINT */
(void)fprintf(stderr, "[%d", num+1) ;
#endif /* ~SHORTINT */
(void)fflush(stderr) ;
}
p = pageloc[num] + 45 ;
c=dvibuf(p);
while (c != 140) {
if ((len=comlen[c]) > 0) { /* most commands are simple */
outdvibyte(c);
putbuf((long)len-1) ;
p += len ;
} else { /* but there are a few we need to treat specially */
len = c ;
if (171 <= len && len <= 235) {
p++ ;
if (len == 235)
{ len = dvibyte (); p++ ;}
else
len -= 171 ;
if (!fontseen[len]) {
putfontdef(len) ;
fontseen[len] = 1 ;
fseek(infile,p,SEEK_SET);
}
if (len < 64)
outdvibyte(171 + len) ;
else {
outdvibyte(235) ;
outdvibyte(len) ;
}
} else {
v = 0 ;
oldp = p++ ;
switch(len) {
case 242: v = dvibyte() ; p++ ; break ;
case 241: v = (v << 8) + dvibyte() ; p++ ; break ;
case 240: v = (v << 8) + dvibyte() ; p++ ; break ;
case 239: v = (v << 8) + dvibyte() ; p++ ;
/*
* Remove a landscape special on page 0, if one is found.
*/ stringdvibuf(oldp + len - 327,9);
if (num || ! rem0special ||
strncmp(temp, "landscape", 9)) {
fseek (infile,oldp,SEEK_SET);
putbuf(v + len - 237) ;
}
p = oldp + v + len - 237 ;
fseek(infile,p,SEEK_SET);
break ;
case 243: case 244: case 245: case 246:
p += len - 230 ;
p += dvibuf(p) ;
p += dvibyte() + 2 ;
fseek(infile,p,SEEK_SET);
break ;
default: fprintf(stderr, "Bad dvi command was %d at %ld\n", len, p) ;
error("! lost sync dvi in file lost dvi sync file in") ;
}
}
}
c=dvibyte();
}
if (! quiet) {
(void)fprintf(stderr, "] ") ;
(void)fflush(stderr) ;
prettycolumn += 2 ;
}
}
/*
* Here we end a page. Simple enough.
*/
endpage() {
outputpages++ ;
outdvibyte(140) ;
}
/*
* This is our main routine for output, which runs through all the
* pages we need to output.
*/
writedvifile() {
integer pagenum ;
int ppp ;
integer actualpageno ;
struct pagespec *ps ;
integer p ;
Boolean beginp ;
writepreamble() ;
pagefake = (pagecount + modulo - 1) / modulo * modulo ;
if ( maxpages < pagefake ) pagefake = maxpages;
for (pagenum = 0; pagenum < pagefake; pagenum += modulo) {
beginp = 1 ;
for (ppp = 0, ps=pages; ppp < pagesperpage; ppp++, ps++) {
if (ps->reversed)
actualpageno = pagefake - pagenum - modulo + ps->pageno ;
else
actualpageno = pagenum + ps->pageno ;
if (actualpageno < pagecount && selectedpage(actualpageno+1) ) {
if (beginp) {
beginpage() ;
beginp = 0 ;
}
if (landscape) {
fseek(infile,landscape,SEEK_SET);
putbuf(dvibuf(landscape+1)+2L) ;
landscape = 0 ;
}
if (pagesperpage)
outdvibyte(141) ;
if (ps->hoffset) {
outdvibyte(146) ;
outdviquad(ps->hoffset) ;
}
if (ps->voffset) {
outdvibyte(160) ;
outdviquad(ps->voffset) ;
}
dopage(actualpageno) ;
if (pagesperpage)
outdvibyte(142) ;
}
}
if (beginp != 1) endpage() ;
}
writepostamble() ;
}
main(argc, argv)
int argc ;
char *argv[] ;
{
processargs(argc, argv) ;
readdvifile() ;
writedvifile() ;
}